package controllers.mockController;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Random;

import model.Model;

import contract.EmployeeContract;
import contract.EventContract;
import event.Event;
import event.Event.EventType;
import event.Event.PreparationType;
import event.PrePreparationState;
import event.PreparationState;
import event.ProgresState;

import budget.Budget;
import budget.Request;
import budget.Service;
import budget.Service.ServiceType;

import person.Customer;
import person.Employee;
import person.Employee.Role;
import person.Guest;
import person.Person;
import person.User;
import warehouse.Gazebo;
import warehouse.Table;
import warehouse.Resource;

public class MockDataSource {
	public MockDataSource(){
		generateCustomers();
		generateEvents();
		generateEmployees();
		generateGuests();
		generateGazebo();
		generateTable();
		generateService();
		generateRequests();
		generateBudgets();
		generateEventContracts();
		generateEmployeeContracts();
		
	}
	
	private void generateEmployees(){
		this.generatedEmployees=new LinkedList<Employee>();
		for (int i=0;i<10;i++){
		this.generatedEmployees.add(new Employee(
				ids++,
				generateString("EmplName"), 
				generateString("EmplSourname"), 
				generateString("EmplTax"), 
				generateString("Emplresidence"), 
				generatePhoneOrFaxNumber(), 
				generatePhoneOrFaxNumber(), 
				generateString("Empl@email.it"), 
				(Role) getRandomEnum(Role.values()), 
				generateString("Emplref"),
				generateDate(new GregorianCalendar()), 
				generateDouble()));
		}
		//this.generatedEmployees.get(0).setAssignedEvent(this.generatedEvents.get(0));
	}
	private void generateCustomers(){
		this.generatedCustomers= new LinkedList<Customer>();
		for (int i=0;i<17;i++){
			this.generatedCustomers.add(
					new Customer(ids++,
								new Person(
								generateString("CustName"), 
								generateString("CustSourname"),
								generateString("CustTax"),
								generateString("CustResidence"),
								generatePhoneOrFaxNumber(), 
								generatePhoneOrFaxNumber(),
								generateString("Cust@email.it")), 
								(Customer.Type) getRandomEnum(Customer.Type.values()), 
								"1230000000000005")
			);
		}
	}
	private void generateGuests(){
		this.generatedGuests=new LinkedList<Guest>();
		for (int i=0;i<0;i++){
			this.generatedGuests.add(
					new Guest(ids++,
							new Person(
							generateString("guestName"), 
							generateString("GuestSourname"), 
							generateString("GuestTax"), 
							generateString("GuestRes"), 
							generatePhoneOrFaxNumber(), 
							generatePhoneOrFaxNumber(),
							generateString("guest@email.it")), 
							(Event) getRandomElem(this.generatedEvents))
			);
		}
	}
	private void generateEvents(){
		this.generatedEvents=new LinkedList<Event>();
		for (int i=0;i<15;i++){
			GregorianCalendar baseDate=new GregorianCalendar();
			GregorianCalendar startDate=this.generateDate(baseDate);
			GregorianCalendar endDate=this.generateDate(startDate);
			this.generatedEvents.add(
					new Event(
							ids++,
							generateString("evtName"), 
							(EventType)getRandomEnum(EventType.values()), 
							(PreparationType)getRandomEnum(PreparationType.values()),
							(Event.ServiceType)getRandomEnum(Event.ServiceType.values()),
							startDate,
							endDate,
							generateString("evtPlace"),
							getRandomInt(1000))
			);
		}
		for (int i=0;i<1;i++){
			GregorianCalendar baseDate=new GregorianCalendar();
			GregorianCalendar startDate=this.generateDate(baseDate);
			GregorianCalendar endDate=this.generateDate(startDate);
			int guest = getRandomInt(1000);
			this.generatedEvents.add(
					new Event(
							ids++,
							generateString("evtName"), 
							(EventType)getRandomEnum(EventType.values()), 
							(PreparationType)getRandomEnum(PreparationType.values()),
							(Event.ServiceType)getRandomEnum(Event.ServiceType.values()),
							startDate,
							endDate,
							generateString("evtPlace"),
							guest,
							new PrePreparationState(guest, guest)
			));
		}
		for (int i=0;i<0;i++){
			GregorianCalendar baseDate=new GregorianCalendar();
			GregorianCalendar startDate=this.generateDate(baseDate);
			GregorianCalendar endDate=this.generateDate(startDate);
			int guest = getRandomInt(1000);
			this.generatedEvents.add(
					new Event(
							ids++,
							generateString("evtName"), 
							(EventType)getRandomEnum(EventType.values()), 
							(PreparationType)getRandomEnum(PreparationType.values()),
							(Event.ServiceType)getRandomEnum(Event.ServiceType.values()),
							startDate,
							endDate,
							generateString("evtPlace"),
							guest,
							new PreparationState()
			));
		}
		for (int i=0;i<0;i++){
			GregorianCalendar baseDate=new GregorianCalendar();
			baseDate.add(GregorianCalendar.DAY_OF_MONTH, 3);
			GregorianCalendar startDate=this.generateDate(baseDate);
			startDate.add(GregorianCalendar.DAY_OF_MONTH, 1);
			GregorianCalendar endDate=this.generateDate(baseDate);
			int guest = getRandomInt(1000);
			this.generatedEvents.add(
					new Event(
							ids++,
							generateString("evtName"), 
							(EventType)getRandomEnum(EventType.values()), 
							(PreparationType)getRandomEnum(PreparationType.values()),
							(Event.ServiceType)getRandomEnum(Event.ServiceType.values()),
							startDate,
							endDate,
							generateString("evtPlace"),
							guest,
							new ProgresState(new ArrayList<Resource>())
			));
		}
	}
	private void generateGazebo(){
		this.generatedGazebo=new LinkedList<Gazebo>();
		for (int i=0;i<100;i++){
			this.generatedGazebo.add(
					new Gazebo(ids++,true,getRandomInt(30),getRandomInt(10)));
		}
		
	}
	private void generateTable(){
		this.generatedTable=new LinkedList<Table>();
		for (int i=0;i<100;i++){
			this.generatedTable.add(
					new Table(ids++, true, i, getRandomInt(8)));
		}
	}
	
	private void generateService(){
		this.generatedServices=new LinkedList<Service>();
		for (int i=0;i<30;i++){
			this.generatedServices.add(
					new Service(
							ids++, 
							(ServiceType)getRandomEnum(ServiceType.values()),
							generateString("service"),
							generateDouble(),
							getRandomBool(),
							getRandomBool(),
							getRandomBool()
							)
			);
		}
	}
	private void generateBudgets(){
		this.generatedBudgets=new LinkedList<Budget>();
		for (int i=0;i<this.generatedRequests.size()-10;i++){
			this.generatedBudgets.add(
					new Budget(
							ids++, 
							generateDouble(), 
							generateDouble(),
							generateDate(new GregorianCalendar()), 
							this.generatedRequests.get(i),
							this.generatedServices
							)
			);
		}
	}
	private void generateEmployeeContracts(){
		this.generatedEmployeeContracts=new LinkedList<EmployeeContract>();
	}
	private void generateEventContracts(){
		this.generatedEventContracts=new LinkedList<EventContract>();
		for (int i=0;i<this.generatedBudgets.size();i++){
			GregorianCalendar baseDate=new GregorianCalendar();
			GregorianCalendar startDate=this.generateDate(baseDate);
			GregorianCalendar endDate=this.generateDate(startDate);
			this.generatedEventContracts.add(
				new EventContract(
						ids++,
						startDate, 
						endDate,
						generateString("EvtContractClauses"),
						this.generatedBudgets.get(i)
			));
		}
	}
	private void generateRequests(){
		this.generatedRequests=new LinkedList<Request>();
		for (int i=0;i<15;i++){
			this.generatedRequests.add(
					new Request(ids++, new GregorianCalendar(),
							this.generatedEvents.get(i),
							generateString("ReqMemo"), 
							(Customer)getRandomElem(generatedCustomers))
					);
		}
	}
	private int getRandomInt(int maxValue){
		return (int) ((Math.random()*1000)%maxValue+1);
	}
	private Object getRandomElem(LinkedList<?> list){
		LinkedList<?> myList=(LinkedList<?>) list.clone();
		Collections.shuffle(myList);
		return myList.getFirst();
	}
	@SuppressWarnings("unused")
	private LinkedList<Object> getRandomElems(LinkedList<?> list){
		LinkedList<Object> elems=new LinkedList<Object>();
		elems.add(this.getRandomElem(list));
		return elems;
	}
	private Double generateDouble(){
		double numberToFormat = (Math.random()*10)%3;
		NumberFormat formattatore = NumberFormat.getNumberInstance();
		formattatore = NumberFormat.getInstance(Locale.ITALY); //in base alla lingua
		formattatore.setMaximumFractionDigits(2);
		return Double.parseDouble(formattatore.format(numberToFormat).replace(',', '.'));
	}
	
	private GregorianCalendar generateDate(GregorianCalendar calToPost){
		int giorni = new Random().nextInt(7)+4;
		calToPost.add(Calendar.DAY_OF_MONTH, giorni);
		return calToPost;
	}

	private Enum<?> getRandomEnum(Enum<?>[] enumerative){
		int rnd=(int) ((Math.random()*100)%enumerative.length);
		return enumerative[rnd];
	}
	private String generateString(String prefix){
		return prefix+"_"+ids++;
	}
	
	private String generatePhoneOrFaxNumber(){
		String n = "";
		int i = new Random().nextInt(1000);
		if(i<100)
			n="0"+i;
		else
			n=""+i;
		n = n+" "+n+n;
		return n;
	}
	
	private boolean getRandomBool(){
		int rnd=(int) ((Math.random()*10)%2);
		if (rnd==1)return true;
		else return false;

	}
	public void registerUser(User u, String userName, String password) throws Exception{
		for(String s : users.keySet()){
			if(s.startsWith(userName))
				throw new Exception();
		}
		users.put(userName+password, u);
	}
	
	public User getUser(String type){
		if (type.equalsIgnoreCase("customer")){
				return (User) getRandomElem(this.generatedCustomers);
		}else if (type.equalsIgnoreCase("rapresentant")){
				for (Employee em:this.generatedEmployees){
					if (em.getRole()==Employee.Role.RAPRESENTANT)
						return em;
				}
		}else if (type.equalsIgnoreCase("admin")) return admin;
		return null;
	}
	public String getToken(String userNm, String pwd){
		User usr=this.getUser(userNm);
		if(usr!=null && pwd.equalsIgnoreCase("test")){
			String token="cldncnwfoe"+((long)(Math.random()*1000)%1000);
			sessions.put(token, usr);
			return token;
		}else return null;
	}
	public void unableToken(String token){
		sessions.remove(token);
	}
	public User getCurrentLogged(String token){
		return sessions.get(token);
	}
	private LinkedList<Model> getAllModels() {
		LinkedList<Model> models=new LinkedList<Model>();
		models.add(admin);
		models.addAll(generatedCustomers);
		models.addAll(generatedBudgets);
		models.addAll(generatedEmployeeContracts);
		models.addAll(generatedEmployees);
		models.addAll(generatedEventContracts);
		models.addAll(generatedEvents);
		models.addAll(generatedGazebo);
		models.addAll(generatedGuests);
		models.addAll(generatedRequests);
		models.addAll(generatedServices);
		models.addAll(generatedTable);
		return models;
	}
	public Model getElem(long id){
		LinkedList<Model> models =this.getAllModels();
		for(Model m:models){
			if (m.getId()==id)return m;
		}
		return null;
	}
	public long getLastId(){
		return ids++;
	}
	public LinkedList<Employee> getGeneratedEmployees() {return generatedEmployees;}
	public LinkedList<Customer> getGeneratedCustomers() {return generatedCustomers;}
	public LinkedList<Guest> getGeneratedGuets() {return generatedGuests;}
	public LinkedList<Gazebo> getGeneratedGazebo() {return generatedGazebo;}
	public LinkedList<Event> getGeneratedEvents() {return generatedEvents;}
	public LinkedList<Table> getGeneratedTable() {return generatedTable;}
	public LinkedList<Service> getGeneratedServices() {return generatedServices;}
	public LinkedList<Budget> getGeneratedBudgets() {return generatedBudgets;}
	public LinkedList<EmployeeContract> getGeneratedEmployeeContracts() {return generatedEmployeeContracts;}
	public LinkedList<EventContract> getGeneratedEventContracts() {return generatedEventContracts;}
	public LinkedList<Request> getGeneratedRequests() {return generatedRequests;}
	public LinkedList<Request> getGeneratedRequests(Person pers){
		LinkedList<Request> lst=new LinkedList<Request>();
		for(Request req:this.generatedRequests){if(req.getCustomer().equals(pers))lst.add(req);}
		return lst;
	}
	private static HashMap<String,User> sessions=new HashMap<String,User>();
	private static HashMap<String,User> users=new HashMap<String,User>();
	private Root admin=new Root();
	private LinkedList<Employee> generatedEmployees;
	private LinkedList<Customer> generatedCustomers;
	private LinkedList<Guest> generatedGuests;
	private LinkedList<Gazebo> generatedGazebo;
	private LinkedList<Event> generatedEvents;
	private LinkedList<Table> generatedTable;
	private LinkedList<Service> generatedServices;
	private LinkedList<Budget> generatedBudgets;
	private LinkedList<EmployeeContract> generatedEmployeeContracts;
	private LinkedList<EventContract> generatedEventContracts;
	private LinkedList<Request> generatedRequests;
	private static Long ids=2L;
}
